mod articles;
mod comment;
mod search;
mod upload;

use crate::search::{self as search_index, Doc2Index, DocFromIndexOuter, TanAction};
use crate::GlobalState;
use crossbeam::channel;
use serde_json::json;
use tide::{self, http::mime, utils::After, Response, StatusCode};

pub fn route(state: GlobalState) -> anyhow::Result<tide::Server<GlobalState>> {
    let (tan_index_tx, tan_index_rx) =
        channel::unbounded::<(TanAction, String, Option<Doc2Index>)>();
    let (tan_query_tx, tan_query_rx) = channel::unbounded::<Vec<DocFromIndexOuter>>();
    let (tan_event_tx, _tan_event_rx) = channel::unbounded::<bool>();

    search_index::run_tantivy(tan_event_tx, tan_index_rx, tan_query_tx);

    // let tempDir = TempDirState::try_new().unwrap();
    // let mut api = tide::with_state(TempDirState::try_new()?);
    let mut api = tide::with_state(state);

    api.with(After(|response: Response| async move {
        let response = match response.status() {
            StatusCode::NotFound => Response::builder(404)
                .content_type(mime::JSON)
                .body(json!({ "status": 0, "error": "not found"}))
                .build(),

            StatusCode::InternalServerError => Response::builder(500)
                .content_type(mime::JSON)
                .body(json!({ "status": 0, "error": "server error"}))
                .build(),

            _ => response,
        };

        Ok(response)
    }));

    api.with(upload::TempDirMiddleware::new()?);

    api.at("/search")
        .with(search::SearchMiddleware::new(tan_index_tx, tan_query_rx))
        .get(search::search_get);

    api.at("/upload/:file")
        .get(upload::upload_file)
        .post(upload::upload);

    api.at("/article")
        .get(articles::index)
        .post(articles::create);

    api.at("/article/:id")
        .get(articles::show)
        .post(articles::update)
        .delete(articles::delete);

    api.at("/comment").get(comment::index).post(comment::create);

    api.at("/comment/:id")
        .get(comment::show)
        .post(comment::update)
        .delete(comment::delete);

    Ok(api)
}
